package 线程通信.管程法;

//生产消费者模型---》使用缓冲区解决问题：管程法
//创建一个缓存区用于管理多个线程的使用，单个线程只需要做自己的工作就好线程的等待和唤醒是缓冲区来管理
public class test {
    public static void main(String[] args) {
        hcq hcq = new hcq();
        scz scz = new scz(hcq);
        xfz xfz = new xfz(hcq);
        new Thread(scz).start();
        new Thread(xfz).start();
    }
}

/**
 * 生产者
 */
class scz implements Runnable {
    hcq hcq;

    public scz(hcq hcq) {
        this.hcq = hcq;
    }

    public scz() {

    }

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println("生产了" + i + "个");
            hcq.push(new cp(i));
        }
    }
}

/**
 * 消费者
 */
class xfz implements Runnable {
    hcq hcq;

    public xfz(hcq hcq) {
        this.hcq = hcq;
    }

    public xfz() {

    }

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println("消费了" + hcq.pop().getId());
        }
    }
}

/**
 * 产品
 */
class cp {
    private int id;
    private String name;

    public cp() {
    }

    public cp(int id) {
        this.id = id;
    }

    public cp(String name) {
        this.name = name;
    }

    public cp(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

/**
 * 缓冲区
 */
class hcq {
    //定义一个容器
    cp[] cp1 = new cp[10];
    //定义一个计数器
    private int x = 0;

    //生产者放入产品
    public synchronized void push(cp cp) {
        //判断容器有没有满，如果满了就通知消费者消费
        if (cp1.length == x) {
            //通知消费者消费,生产者等待
            try {
                this.wait();//使调用这个方法的线程等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        cp1[x] = cp;
        x++;
        //通知消费者消费
        this.notify();//唤醒一个处于等待的进程
    }

    //消费者消费
    public synchronized cp pop() {
        //判断容器是否有，判断是否可以消费
        if (x == 0) {
            //等待生产者生产，消费者等待
            try {
                this.wait();//使调用这个方法的线程等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //消费
        x--;
        cp cp2 = cp1[x];

        //消费了通知生产者生产
        this.notify();//唤醒一个处于等待的进程
        return cp2;
    }
}